#include "thread.h"
#include <iostream>
using std::cout;
using std::endl;

Thread::Thread()
{
    m_running = false;
#ifdef _WIN32
    InitializeCriticalSection(&m_criticalSection);
#else
    pthread_mutex_init(&m_mutex, NULL);
#endif
}

Thread::~Thread()
{
    if (m_running)
    {
#ifdef _WIN32
        WaitForSingleObject(m_thread, INFINITE);
        DeleteCriticalSection(&m_criticalSection);
#else
        pthread_join(m_pthread, NULL);
        pthread_mutex_destroy(&m_mutex);
#endif
    }
}

void Thread::start()
{
    if (!m_running)
    {
#ifdef _WIN32
        m_thread = CreateThread(0, 0, &Thread::threadFunc, this, 0, 0);
#else
        pthread_create(&m_pthread, NULL, Thread::threadFunc, this);
#endif
    }
}

#ifdef _WIN32
DWORD __stdcall Thread::threadFunc(LPVOID arg)
#else
void* Thread::threadFunc(void* arg)
#endif
{
    Thread* thread = (Thread*)arg;
    thread->lock();
    if (thread->m_running)
    {
        thread->unlock();
        return 0;
    }

    thread->m_running = true;
    thread->unlock();

    thread->run();

    thread->lock();
    thread->m_running = false;
    thread->unlock();
    cout << "Thread " << thread << " now exits" << endl;
    return 0;
}

void Thread::lock()
{
#ifdef _WIN32
    EnterCriticalSection(&m_criticalSection);
#else
    pthread_mutex_lock(&m_mutex);
#endif
}

void Thread::unlock()
{
#ifdef _WIN32
    LeaveCriticalSection(&m_criticalSection);
#else
    pthread_mutex_unlock(&m_mutex);
#endif
}

void Thread::join()
{
    if (m_running)
    {
#ifdef _WIN32
        WaitForSingleObject(m_thread, INFINITE);
#else
        pthread_join(m_pthread, NULL);
#endif
    }
}
